import random
import string
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from sqlalchemy.util import b64encode, b64decode
import time
import base64
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import json
import os
import hashlib

from ..WxConfigParser import ConfigParser


class WxPayTool:
    def __init__(self):
        con = ConfigParser()
        self.mchid = con.get_mch_id()
        self.serial_no = con.get_serial_no()
        self.secret = con.get_appsecret()
        self.appid = con.get_appid()

    def get_sign_str(self, **kwargs):
        """
        构造签名串
        :return:
        """
        url = kwargs.get("url")
        data = kwargs.get("data")
        timestamp_str = kwargs.get("timestamp")
        method = kwargs.get('method')
        nonce_str = kwargs.get('nonce_str')
        sign_str = "{}\n{}\n{}\n{}\n{}\n".format(method, url, timestamp_str, nonce_str, data)
        return self.get_sign(sign_str=sign_str)

    def get_headers(self, data="", method='GET', url='/v3/certificates'):
        """
        获取请求头
        :return:
        """
        timestamp_str = self.get_timestamp()  # 时间戳
        nonce_str = self.get_random_str()  # 随机字符串
        sign = self.get_sign_str(url=url, data=data, method=method, timestamp=timestamp_str, nonce_str=nonce_str)
        headers = {
            "Content-Type": "application/json",
            "Authorization": 'WECHATPAY2-SHA256-RSA2048 ' + f'mchid="{self.mchid}",nonce_str="{nonce_str}",signature="{sign}",timestamp="{timestamp_str}",serial_no="{self.serial_no}"',
            "Accept": "application/json"
        }
        return (headers, timestamp_str, nonce_str)

    def decrypt_to_str(self, **kwargs):
        """
        解密返回信息
        :param kwargs:
        :return:
        """
        ciphertext = kwargs.get("ciphertext")
        associated_data = kwargs.get("associated_data")
        nonce = kwargs.get("nonce")
        key_byte = str.encode(self.secret)
        nonce_byte = str.encode(nonce)
        associated_data_byte = str.encode(associated_data)
        ciphertext_byte = base64.b64decode(ciphertext)
        aesgcm = AESGCM(key_byte)
        return aesgcm.decrypt(nonce=nonce_byte, data=ciphertext_byte, associated_data=associated_data_byte).decode()

    @staticmethod
    def md5(sign_str: str):
        """
        md5加密
        """
        m = hashlib.md5()
        m.update(sign_str.encode('utf-8'))
        return m.hexdigest()

    def get_md5_sign_str(self, info):
        """
        md5 签名
        """
        pay_key = "ialn3sltm2qwxd2njxx1v2ohb42lfogv"
        temp = "&".join(
            ["{0}={1}".format(k, info[k]) for k in sorted(info)] + ["{0}={1}".format("key", pay_key, ), ])
        print(temp)
        sign = self.md5(temp).upper()
        return sign

    @staticmethod
    def get_sign(sign_str: str):
        """
        签名串加密
        :param sign_str:
        :return:
        """
        file_path = os.path.dirname(__file__)
        pem_path = os.path.join(file_path, "pem")
        pem_path = os.path.join(pem_path, "apiclient_key.pem")
        with open(pem_path, 'rb') as f:
            private_key = f.read()
            rsa_key = RSA.import_key(private_key)
            signer = pkcs1_15.new(rsa_key)
            digest = SHA256.new(sign_str.encode("utf-8"))
            sign = base64.b64encode(signer.sign(digest)).decode("utf-8")
            return sign

    @staticmethod
    def get_random_str():
        """
        获取随机请求串
        :return:
        """
        return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))

    @staticmethod
    def get_timestamp():
        """
        获取时间戳
        :return:
        """
        return str(int(time.time()))

    def make_mini_pay_info(self, **kwargs):
        """
        生成小程序调起支付信息
        """
        appid = kwargs.get("appId")
        prepay_id = kwargs.get("prepay_id")
        timestamp = kwargs.get("timestamp")
        nonceStr = kwargs.get("nonceStr")
        package = f'prepay_id={prepay_id}'
        pay_str = f"{appid}\n{timestamp}\n{nonceStr}\n{package}\n"
        paySign = self.get_sign(pay_str)
        pay_info = {
            "appId": appid,
            "timeStamp": timestamp,
            "nonceStr": nonceStr,
            "package": package,
            "signType": "RSA",
            "paySign": paySign
        }
        return pay_info

    def verify_signature(self, **kwargs):
        """
        验证平台签名
        """
        # 取参数
        signature = kwargs.get("signature")
        timestamp_str = kwargs.get("timestamp_str")
        nonce = kwargs.get("nonce")
        serial = kwargs.get("serial")
        post_data = kwargs.get("post_data")
        check_data = f"{timestamp_str}\n{nonce}\n{post_data}\n"
        result = self.verify(signature=signature, serial=serial, check_data=check_data)
        print(result)

    def verify(self, **kwargs):
        """
        验证签名
        """
        signature = kwargs.get("signature")
        check_data = kwargs.get("check_data")
        serial = kwargs.get("serial")
        # 取证书
        file_path = os.path.dirname(__file__)
        pem_path = os.path.join(file_path, f"{serial}.pem")
        with open(pem_path, "rb") as f:
            certificate = f.read()
            signature = base64.b64decode(signature)
            key = RSA.import_key(certificate)
            verifier = pkcs1_15.new(key)
            hash_obj = SHA256.new(check_data.encode("utf8"))
            return verifier.verify(hash_obj, signature=signature)
